package com.wanji.gateway.protocol;


import com.wanji.gateway.config.ProtocolConfig;
import com.wanji.gateway.util.CIDRUtil;
import com.wanji.protocol.api.Protocol;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

// SPI协议加载器
@Slf4j
@Service
@RequiredArgsConstructor
public class ProtocolLoader {
    private final Map<String, Protocol> protocolImpls = new ConcurrentHashMap<>();
    private final ProtocolConfig protocolConfig;
    // 类加载器
    private DynamicClassLoader classLoader;

    @PostConstruct
    public void init() {
        log.info("初始化协议");
        // 创建动态类加载器
        String sdkDir = protocolConfig.getPath();
        File dir = new File(sdkDir);
        if (!dir.exists() || !dir.isDirectory()) {
            log.warn("SDK目录不存在或不是目录: {}", sdkDir);
            return;
        }
        try {
            classLoader = new DynamicClassLoader(sdkDir, getClass().getClassLoader());
            // 加载协议实现
            loadProtocols();
        } catch (IOException e) {
            log.error("动态协议加载器初始化失败", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 从指定目录加载所有协议实现
     */
    public void loadProtocols() {
        String sdkDir = protocolConfig.getPath();
        log.info("开始从目录加载协议: {}", sdkDir);
        try {
            // 清空现有协议
            protocolImpls.clear();

            // 扫描目录中的所有JAR包
            List<File> jarFiles = new ArrayList<>();
            File dir = new File(sdkDir);
            if (dir.exists() && dir.isDirectory()) {
                File[] files = dir.listFiles();
                if (files == null || files.length == 0) {
                    return;
                }
                for (File file : files) {
                    if (file.isFile() && file.getName().endsWith(".jar")) {
                        jarFiles.add(file);
                    }
                }
            }

            // 从每个JAR包中加载协议实现
            for (File jarFile : jarFiles) {
                loadProtocolsFromJar(jarFile);
            }

            log.info("协议加载完成，共加载 {} 个协议实现", protocolImpls.size());
        } catch (Exception e) {
            log.error("加载协议失败", e);
        }
    }

    /**
     * 从单个JAR文件加载协议实现
     */
    private void loadProtocolsFromJar(File jarFile) {
        log.info("从JAR包加载协议: {}", jarFile.getName());

        try {
            // 使用动态类加载器扫描JAR包中的协议实现
            List<Class<? extends Protocol>> protocolClasses =
                    classLoader.scanForType(jarFile.getAbsolutePath(), Protocol.class);

            // 实例化并注册协议
            for (Class<? extends Protocol> protocolClass : protocolClasses) {
                try {
                    // 创建协议实例
                    Protocol protocol = protocolClass.getDeclaredConstructor().newInstance();

                    // 注册协议
                    protocolImpls.put(protocol.protocolType(), protocol);
                    log.info("成功加载协议: {} -> {}", protocol.protocolType(), protocolClass.getName());
                } catch (Exception e) {
                    log.error("实例化协议失败: {}", protocolClass.getName(), e);
                }
            }
        } catch (Exception e) {
            log.error("从JAR包加载协议失败: {}", jarFile.getName(), e);
        }
    }

    public Protocol loadProtocolForIp(String ip) {
        // 根据IP匹配协议类型
        String protocolType = resolveProtocolType(ip);
        Protocol prototype = protocolImpls.get(protocolType);
        return prototype.clone();
    }

    private String resolveProtocolType(String ip) {
        // 方法1: 从设备注册表查找
        /*Optional<Device> deviceOpt = deviceRegistry.findByIp(ip);
        if (deviceOpt.isPresent()) {
            return deviceOpt.get().getProtocolType();
        }*/

        // 方法2: 根据配置文件中的IP段映射判断
        if (protocolConfig.getMapping() != null) {
            for (Map.Entry<String, String> entry : protocolConfig.getMapping().entrySet()) {
                String ipPattern = entry.getKey();
                String protocolType = entry.getValue();

                if (CIDRUtil.isIpInCidrRange(ip, ipPattern)) {
                    return protocolType;
                }
            }
        }

        // 返回默认协议
        return protocolConfig.getDefaultProtocol();
    }
}
